"""Logging module."""

from cStringIO import StringIO
from logging import handlers
import logging
import os
import sys
import traceback

_origStdout = sys.stdout
_origStderr = sys.stderr

class DummyFobj(object):

    def _noop(self, *args, **kwargs):
        pass

    write = flush = _noop

class DummyWrite(object):

    def __init__(self, cb):
        self._callback = cb

    def write(self, what):
        self._callback(what)

def exceptionHook(type, value, tb):
    def _logMsg(msg):
        logging.log(logging.FATAL, msg)
        _origStderr.write(msg + "\n")
    _logMsg("----= UNHALTED EXCEPTION =----")
    _str = StringIO()
    traceback.print_exception(type, value, tb, None, _str)
    _str.seek(0, 0)
    _data = _str.read()
    for _line in _data.splitlines():
        _logMsg(_line)
    _logMsg("----= END =---")

class Logger(object):

    logFileName = "program.log"
    logFormat = "[%(levelname)s] %(message)s"

    levels = ("debug", "info", "error", "exception")

    _rootLogger = None

    def __init__(self):
        logging.basicConfig(
            level=logging.DEBUG,
            format=self.logFormat,
            stream=DummyFobj()
        )
        self._rootLogger = logging.getLogger('')
        # now to populate logging methods
        for _name in self.levels:
            _func = self._getLoggerFunc(_name)
            if not hasattr(self, "log_" + _name):
                setattr(self, "log_" + _name, _func)

    def _getLoggerFunc(self, name):
        _loggerFunc = getattr(self._rootLogger, name)
        return lambda msg, *args: _loggerFunc(msg % args)

    def close(self):
        logging.shutdown()

    def addLoggingDir(self, dir):
        _handler = handlers.RotatingFileHandler(
            os.path.join(dir, self.logFileName),
            "a", 0, 10)
        _formatter = logging.Formatter("%(asctime)s " + self.logFormat)
        _handler.setFormatter(_formatter)
        _handler.doRollover()
        self._rootLogger.addHandler(_handler)
        self.log_info("Directory logger %s added", dir)

    def log_exception(self, msg, *args):
        logging.log(logging.FATAL, msg % args)
        _str = StringIO()
        traceback.print_exc(None, _str)
        _str.seek(0, 0)
        _data = _str.read()
        for _line in _data.splitlines():
            logging.log(logging.FATAL, _line)

    def setSysHooks(self):
        # set uncaught exception hook
        sys.excepthook = exceptionHook
        sys.stdout = DummyWrite(self.onStdout)
        sys.stderr = DummyWrite(self.onStderr)


    def onStdout(self, msg):
        for _line in msg.splitlines():
            logging.log(logging.INFO, "STDOUT> " + _line)
        _origStdout.write(msg)

    def onStderr(self, msg):
        for _line in msg.splitlines():
            logging.log(logging.INFO, "STDERR> " + _line)
        _origStdout.write(msg)

def getLogger():
    return Logger()

# vim: set sts=4 sw=4 et :
